package org.clockworkmages.games.anno1186.scripting;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.clockworkmages.games.anno1186.GameAreaService;
import org.clockworkmages.games.anno1186.GameData;
import org.clockworkmages.games.anno1186.GameDataService;
import org.clockworkmages.games.anno1186.GameGuiService;
import org.clockworkmages.games.anno1186.GameState;
import org.clockworkmages.games.anno1186.GameStateService;
import org.clockworkmages.games.anno1186.Injected;
import org.clockworkmages.games.anno1186.model.map.tactical.GameArea;
import org.clockworkmages.games.anno1186.model.map.tactical.GameAreaDO;
import org.clockworkmages.games.anno1186.util.RollUtil;

public class UtilScriptingWrapper {

	@Injected
	private GameStateService gameStateService;
	@Injected
	private GameDataService gameDataService;
	@Injected
	private GameAreaService gameAreaService;
	@Injected
	private GameGuiService gameGuiService;

	public double positiveOrZero(double value) {
		if (value >= 0) {
			return value;
		} else {
			return 0;
		}
	}

	public double random(int range) {
		return RollUtil.random(range);
	}

	/**
	 * A random generator that stores the generated value in a static map so
	 * that the same condition will return the same result for a single
	 * Situation, even if the user switches to the Inventory, Spellbook or Stats
	 * screen and then goes back to the current Situation.
	 * 
	 * E.g. the player is in a room in a dungeon and he has a 50% chance to spot
	 * a hidden lever. He rolls succesfully and spos the lever, and get an
	 * aditional Option to pull it. But he goes to the Inventory screen and then
	 * goes back to the Situation (dungeon room) screen. At that point we do not
	 * want to re-roll the perception test, we want to reuse the original
	 * result.
	 * 
	 * 
	 * @param range
	 * @param id
	 * @return
	 */
	public double situationRandom(int range, String cacheKey) {

		int stackSize = gameStateService.getGameState().getSituationStack()
				.size();
		Map<Integer, Map<String, Double>> situationRandoms = gameStateService
				.getGameState().getSituationCachedRandoms();
		Map<String, Double> cachedValues = situationRandoms.get(stackSize);
		if (cachedValues == null) {
			cachedValues = new HashMap<String, Double>();
			situationRandoms.put(stackSize, cachedValues);
		}
		Double cachedValue = cachedValues.get(cacheKey);
		if (cachedValue == null) {
			cachedValue = RollUtil.random(range);
			cachedValues.put(cacheKey, cachedValue);
		}
		return cachedValue;
	}

	public int chance(double pow) {
		return RollUtil.chance(pow);
	}

	public int chanceBase50(double pow) {
		return RollUtil.chanceBase50(pow);
	}

	public boolean roll(double pow) {
		return RollUtil.roll(pow);
	}

	public boolean roll(double pow, String cacheKey) {
		double roll = situationRandom(100, cacheKey);
		int chance = chance(pow);
		return roll <= chance;
	}

	public boolean rollBase50(double pow) {
		return RollUtil.rollBase50(pow);
	}

	public boolean rollBase50(double pow, String cacheKey) {
		double roll = situationRandom(100, cacheKey);
		int chance = chanceBase50(pow);
		return roll <= chance;
	}

	/**
	 * Same as {@link #random(int, String)}, this method generates or gets an
	 * existing value of a random. The values generated by this method are
	 * cached for a duration of one game-day (until the character goes to sleep)
	 * and then get evicted.
	 * 
	 * @param range
	 * @param id
	 * @return
	 */
	public double dailyRandom(int range, String dailyCacheKey) {
		Map<String, Double> dailyCachedRandoms = gameStateService
				.getGameState().getDailyCachedRandoms();
		Double cachedValue = dailyCachedRandoms.get(dailyCacheKey);
		if (cachedValue == null) {
			cachedValue = Math.random() * range;
			dailyCachedRandoms.put(dailyCacheKey, cachedValue);
		}
		return cachedValue;
	}

	public int getHour() {
		Date date = new Date(gameStateService.getGameState().getTime());
		int hour = date.getHours();
		return hour;
	}

	public boolean isDay() {
		Date date = new Date(gameStateService.getGameState().getTime());
		int hour = date.getHours();
		if (hour >= 6 && hour <= 18) {
			return true;
		} else {
			return false;
		}
	}

	public boolean isNight() {
		Date date = new Date(gameStateService.getGameState().getTime());
		int hour = date.getHours();
		if (hour <= 5 || hour >= 22) {
			return true;
		} else {
			return false;
		}
	}

	public boolean fetishesEnabled(String... fetishIds) {
		Set<String> fetishesEnabled = gameStateService.getGameState()
				.getFetishesEnabled();
		for (String fetishId : fetishIds) {
			if (!fetishesEnabled.contains(fetishId)) {
				return false;
			}
		}
		return true;
	}

	public void goToLocation(String gameAreaId, int x, int y) {

		GameData gameData = gameDataService.getGameData();
		GameAreaDO gameAreaDO = gameData.getGameAreas().get(gameAreaId);

		GameArea gameArea = gameAreaService.fromDO(gameAreaDO);

		GameState gameState = gameStateService.getGameState();
		gameState.setGameArea(gameArea);

		gameState.setLocalMapX(x);
		gameState.setLocalMapY(y);

		gameGuiService.getLocalMapPanel().repaint();

	}
}
